﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;

using Dapper;

using DapperExtensions;

namespace System.Data
{
    public class DapperRepository<TEntity> : IRepository<TEntity> where TEntity : Entity
    {
        private IDbHandleBase dbHandleBase = null;
        protected string _tableName = "";
        public DapperRepository(string tableName = "")
        {
            dbHandleBase = DbFactory.DbHelper();
            if (string.IsNullOrWhiteSpace(tableName))
            {
                _tableName = dbHandleBase.GetDbTableName<TEntity>();
            }
            else
            {
                _tableName = tableName.Trim();
            }
        }

        #region  BasicMethod
        public IDbHandleBase DBA { get { return dbHandleBase; } }
        public virtual bool Exists(string Id)
        {
            if (string.IsNullOrWhiteSpace(Id)) throw new ArgumentNullException(nameof(Id));
            var allrecords = dbHandleBase.Get<TEntity>(Id);
            return allrecords != null;
        }
        public virtual bool Exist(Expression<Func<TEntity, bool>> predicate = null)
        {
            var queryResult = DynamicQuery.GetDynamicQuery(_tableName, predicate);
            var result = dbHandleBase.ExecuteScalar(queryResult.Sql, (object)queryResult.Param);
            return result != null;
        }
        public virtual string Add(TEntity model)
        {
            if (model == null) throw new ArgumentNullException(nameof(model));
            model.Create();
            var insert = dbHandleBase.Insert(model);
            return insert;
        }
        public virtual void BatchAdd(IEnumerable<TEntity> models)
        {
            models.ForEach(m => m.Create());
            dbHandleBase.Insert(models);
        }
        public virtual bool Update(TEntity model)
        {
            if (model == null) throw new ArgumentNullException(nameof(model));
            model.Modify();
            var insert = dbHandleBase.Update(model);
            return insert;
        }
        public virtual TEntity AddOrUpdate(TEntity model)
        {
            if (model == null) throw new ArgumentNullException(nameof(model));
            if (Exists(model.ID))
            {
                Update(model);
                return model;
            }
            else
            {
                Add(model);
                return model;
            }
        }
        /// <summary>
        /// 批量删除数据 1,2,3
        /// </summary>
        public virtual bool Delete(string Idlist)
        {
            if (string.IsNullOrWhiteSpace(Idlist)) throw new ArgumentNullException(nameof(Idlist));
            var idarr = Idlist.Split(",");
            StringBuilder strSql = new StringBuilder();
            strSql.Append("delete from [" + _tableName + "] ");
            strSql.Append(" where Id in (" + idarr.ToSql(false) + ")  ");
            int result = dbHandleBase.ExecuteNonQuery(strSql.ToString());
            if (result > 0)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        public virtual bool Delete(params TEntity[] models)
        {
            if (models == null)
                throw new ArgumentNullException(nameof(models));

            foreach (var item in models)
            {
                item.Remove();
                return dbHandleBase.Delete<TEntity>(item);
            }
            return true;
        }
        public virtual bool Delete(Expression<Func<TEntity, bool>> predicate = null)
        {
            var queryResult = DynamicQuery.GetDynamicQuery(_tableName, predicate);
            var result = dbHandleBase.ExecuteNonQuery(queryResult.Sql, (object)queryResult.Param);
            return result > 0;
        }
        public virtual bool DeleteWhere(string sqlWhere)
        {
            if (string.IsNullOrWhiteSpace(sqlWhere)) throw new ArgumentNullException(nameof(sqlWhere));
            string sql = string.Format("delete [{0}] where {1}", _tableName, sqlWhere);
            int result = dbHandleBase.ExecuteNonQuery(sql);
            return result > 0;
        }
        public virtual bool UpdateField(string keyId, string fieldName, string fieldValue)
        {
            if (string.IsNullOrWhiteSpace(keyId)) throw new ArgumentNullException(nameof(keyId));
            if (string.IsNullOrWhiteSpace(fieldName)) throw new ArgumentNullException(nameof(fieldName));
            if (string.IsNullOrWhiteSpace(fieldValue)) throw new ArgumentNullException(nameof(fieldValue));

            string sql = string.Format(@"update [" + _tableName + "] set {0}='{1}' where ID='{2}'", fieldName, fieldValue, keyId);
            int result = dbHandleBase.ExecuteNonQuery(sql);
            return result > 0;
        }
        public virtual TEntity GetById(string Id)
        {
            var result = dbHandleBase.Get<TEntity>(Id);
            return result;
        }
        public virtual List<TEntity> Get(Expression<Func<TEntity, bool>> exp = null)
        {
            return dbHandleBase.GetList(exp).OrderBy(u => u.OrderBy).ToList();
        }
        public virtual List<TEntity> GetByAll(string strWhere = "")
        {
            StringBuilder strSql = new StringBuilder();
            strSql.Append("select * ");
            strSql.Append(" FROM [" + _tableName + "] ");
            if (!string.IsNullOrWhiteSpace(strWhere))
            {
                strSql.Append(" where " + strWhere);
            }
            strSql.Append(" order by OrderBy desc ");
            var filter = Predicates.Field<TEntity>(f => f.ID, Operator.Lt, 100);//取Id<100的TEntity降序数据列表
            var sort = new List<ISort> { Predicates.Sort<TEntity>(f => f.ID, false) };//false降序
            var tt = dbHandleBase.Query<TEntity>(strSql.ToString());
            return tt.ToList();
        }
        public virtual List<TEntity> GetByPage(string strWhere, string orderby = "OrderBy desc", int startIndex = 1, int endIndex = 10)
        {
            int i_inde, i_end;
            i_end = startIndex * endIndex;
            i_inde = (startIndex - 1) * endIndex + 1;
            StringBuilder strSql = new StringBuilder();
            strSql.Append("SELECT * FROM ( ");
            strSql.Append(" SELECT ROW_NUMBER() OVER (");
            if (!string.IsNullOrEmpty(orderby))
            {
                strSql.Append("order by T." + orderby);
            }
            else
            {
                strSql.Append("order by T.Id desc");
            }
            strSql.Append(")AS Row, T.*  from [" + _tableName + "] T ");
            if (!string.IsNullOrEmpty(strWhere))
            {
                strSql.Append(" WHERE " + strWhere);
            }
            strSql.Append(" ) TT");
            strSql.AppendFormat(" WHERE TT.Row between {0} and {1}", i_inde, i_end);
            var tt = dbHandleBase.Query<TEntity>(strSql.ToString());
            return tt.ToList();
        }
        public virtual int GetTotalCount(string strWhere)
        {
            StringBuilder strSql = new StringBuilder();
            strSql.Append("select count(1) FROM [" + _tableName + "]  ");
            if (!string.IsNullOrWhiteSpace(strWhere))
            {
                strSql.Append(" where " + strWhere);
            }
            object obj = dbHandleBase.ExecuteScalar(strSql.ToString());
            if (obj == null)
            {
                return 0;
            }
            else
            {
                return Convert.ToInt32(obj);
            }
        }
        #endregion  BasicMethod
        public virtual DataTable GetByDataTable(Paging paging)
        {
            int i_inde, i_end;
            i_end = paging.page * paging.rows;
            i_inde = (paging.page - 1) * paging.rows + 1;
            StringBuilder strSql = new StringBuilder();
            strSql.Append("SELECT " + paging.field + " FROM ( ");
            strSql.Append(" SELECT ROW_NUMBER() OVER (");
            if (!string.IsNullOrEmpty(paging.orderby))
            {
                strSql.Append("order by T." + paging.orderby);
            }
            else
            {
                strSql.Append("order by T.Id desc");
            }
            strSql.Append(")AS Row, T.*  from [" + _tableName + "] T ");
            if (!string.IsNullOrEmpty(paging.sqlwhere))
            {
                strSql.Append(" WHERE " + paging.sqlwhere);
            }
            strSql.Append(" ) TT");
            strSql.AppendFormat(" WHERE TT.Row between {0} and {1}", i_inde, i_end);

            var tt = dbHandleBase.ExecuteDataTable(strSql.ToString());
            return tt;
        }
        public virtual JQridPageData GetJGridPageData(Paging paging)
        {
            int total;
            var list = dbHandleBase.GetPageSql<TEntity>(paging.field, _tableName, paging.sqlwhere, paging.orderby, paging.page, paging.rows, out total);
            JQridPageData pageData = new JQridPageData();
            pageData.rows = list;
            pageData.page = paging.page;
            pageData.pageRows = paging.rows;
            pageData.records = total;
            return pageData;
        }
        #region private

        #endregion

    }
}
